package com.eksframework.commons.core.base;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.time.*;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * * 通用日期时间操作类
 *
 * @author: <a href="mailto:chenfenghai@oristartech.com">chenfenghai</a>
 * @version: 1.0
 * @date: 2019-10-21 14:18
 * @blame Android Team
 */
public class EksDate {

    /**
     * 缓存已使用过的DateTimeFormatter
     */
    private static final ConcurrentHashMap<String, DateTimeFormatter> FORMATTER_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();
    /**
     * Number of nanos in a standard milliseconds.
     */
    public static final long NANOS_PER_MILLISECOND = 1000000;
    /**
     * Number of milliseconds in a standard second.
     */
    public static final long MILLIS_PER_SECOND = 1000;
    /**
     * Number of milliseconds in a standard minute.
     */
    public static final long MILLIS_PER_MINUTE = 60000;
    /**
     * Number of milliseconds in a standard hour.
     */
    public static final long MILLIS_PER_HOUR = 3600000;
    /**
     * Number of milliseconds in a standard day.
     */
    public static final long MILLIS_PER_DAY = 86400000;

    /**
     * 广电标准中的一天营业日期的开始时间
     */
    public static final int BUSINESS_START_HOUR = 6;

    /**
     * 分隔符：空格
     */
    public static final String SPLITTER_SPACE = " ";
    /**
     * 分隔符：T
     */
    public static final String SPLITTER_T = "'T'";
    /**
     * 分隔符：Z
     */
    public static final String SPLITTER_Z = "'Z'";
    /**
     * 分隔符：-
     */
    public static final String SPLITTER_DASH = "-";
    /**
     * 分隔符：/
     */
    public static final String SPLITTER_SLASH = "/";
    /**
     * 分隔符：:
     */
    public static final String SPLITTER_COLON = ":";
    /**
     * 分隔符：.
     */
    public static final String SPLITTER_DOT = ".";
    /**
     * 中文：年
     */
    public static final String CN_YEAR = "年";
    /**
     * 中文：月
     */
    public static final String CN_MONTH = "月";
    /**
     * 中文：日
     */
    public static final String CN_DAY = "日";

    /**
     * 年份，使用 yyyy 表示的年份，如 2011
     */
    public static final String PATTERN_YEARS = "yyyy";
    /**
     * 年份，使用 yy 表示的年扮，如 11；
     */
    public static final String PATTERN_YEARS_SHORT = "yy";
    /**
     * 月份，使用 MM 表示的月份，如 05；
     */
    public static final String PATTERN_MONTHS = "MM";
    /**
     * 月份中的天数，使用 dd 表示的天数，如 10
     */
    public static final String PATTERN_DAYS = "dd";
    /**
     * 一天中的小时数（0~23)，使用 HH 表示的小时数，如 18
     */
    public static final String PATTERN_HOURS = "HH";
    /**
     * 一天中的小时数（1~12)，使用 hh 表示的小时数，如 10 (注意 10 有可能是 10 点，也可能是 22 点）
     */
    public static final String PATTERN_HOURS_SHORT = "hh";
    /**
     * 分钟数，使用 mm 表示的分钟数，如 29
     */
    public static final String PATTERN_MINUTES = "mm";
    /**
     * 秒数，使用 ss 表示的秒数，如 38
     */
    public static final String PATTERN_SECONDS = "ss";
    /**
     * 毫秒数，使用 SSS 表示的毫秒数，如 156
     */
    public static final String PATTERN_MILLISECONDS = "SSS";

    /**
     * 格式：yyyyMM
     */
    public static final String PATTERN_YYYYMM_UNION = "yyyyMM";
    /**
     * 格式：yyyyMMdd
     */
    public static final String PATTERN_YYYYMMDD_UNION = "yyyyMMdd";
    /**
     * 格式：yyyy-MM
     */
    public static final String PATTERN_YYYYMM_DASH = "yyyy-MM";
    /**
     * 格式：yyyy-MM-dd
     */
    public static final String PATTERN_YYYYMMDD_DASH = "yyyy-MM-dd";
    /**
     * 格式：yyyy/MM
     */
    public static final String PATTERN_YYYYMM_SLASH = "yyyy/MM";
    /**
     * 格式：yyyy/MM/dd
     */
    public static final String PATTERN_YYYYMMDD_SLASH = "yyyy/MM/dd";
    /**
     * 格式：yyyy年MM月
     */
    public static final String PATTERN_YYYYMM_CN = "yyyy年MM月";
    /**
     * 格式：yyyy年MM月dd日
     */
    public static final String PATTERN_YYYYMMDD_CN = "yyyy年MM月dd日";
    /**
     * 格式：yyyy年MM月dd日HH时
     */
    public static final String PATTERN_YYYYMMDDHH_CN = "yyyy年MM月dd日HH时";
    /**
     * 格式：yyyy-MM
     */
    public static final String PATTERN_YYYYMM = PATTERN_YYYYMM_DASH;
    /**
     * 格式：yyyy-MM-dd
     */
    public static final String PATTERN_YYYYMMDD = PATTERN_YYYYMMDD_DASH;

    /**
     * 格式：HHmm
     */
    public static final String PATTERN_HHMM_UNION = "HHmm";
    /**
     * 格式：HHmmss
     */
    public static final String PATTERN_HHMMSS_UNION = "HHmmss";
    /**
     * 格式：HH:mm
     */
    public static final String PATTERN_HHMM_COLON = "HH:mm";
    /**
     * 格式：HH:mm:ss
     */
    public static final String PATTERN_HHMMSS_COLON = "HH:mm:ss";
    /**
     * 格式：HH时mm分
     */
    public static final String PATTERN_HHMM_CN = "HH时mm分";
    /**
     * 格式：yyyy年MM月dd日HH时
     */
    public static final String PATTERN_YYYYMMDDHHMM_CN = PATTERN_YYYYMMDD_CN + PATTERN_HHMM_CN;
    /**
     * 格式：HH时mm分ss秒
     */
    public static final String PATTERN_HHMMSS_CN = "HH时mm分ss秒";
    /**
     * 格式：HH:mm
     */
    public static final String PATTERN_HHMM = PATTERN_HHMM_COLON;
    /**
     * 格式：HH:mm:ss
     */
    public static final String PATTERN_HHMMSS = PATTERN_HHMMSS_COLON;

    /**
     * 格式：yyyyMMddHHmm
     */
    public static final String PATTERN_YYYYMMDDHHMM_UNION = PATTERN_YYYYMMDD_UNION + PATTERN_HHMM_UNION;
    /**
     * 格式：yyyyMMddHHmmss
     */
    public static final String PATTERN_YYYYMMDDHHMMSS_UNION = PATTERN_YYYYMMDD_UNION + PATTERN_HHMMSS_UNION;
    /**
     * 格式：yyyy-MM-dd HH:mm
     */
    public static final String PATTERN_YYYYMMDDHHMM = PATTERN_YYYYMMDD + SPLITTER_SPACE + PATTERN_HHMM;
    /**
     * 格式：yyyy-MM-dd HH:mm:ss
     */
    public static final String PATTERN_YYYYMMDDHHMMSS = PATTERN_YYYYMMDD + SPLITTER_SPACE + PATTERN_HHMMSS;
    /**
     * 格式：yyyy-MM-dd HH:mm:ss.SSS
     */
    public static final String PATTERN_YYYYMMDDHHMMSSZZZ = PATTERN_YYYYMMDD + SPLITTER_SPACE + PATTERN_HHMMSS + SPLITTER_DOT + PATTERN_MILLISECONDS;
    /**
     * 格式：yyyy-MM-dd'T'HH:mm:ss
     */
    public static final String PATTERN_YYYYMMDDHHMMSS_T = PATTERN_YYYYMMDD + SPLITTER_T + PATTERN_HHMMSS;
    /**
     * 格式：yyyy年MM月dd日HH时mm分ss秒
     */
    public static final String PATTERN_YYYYMMDDHHMMSS_CN = PATTERN_YYYYMMDD_CN + SPLITTER_SPACE + PATTERN_HHMMSS_CN;
    /**
     * 格式：2020-11-06T06:00:00.000Z
     */
    public static final String PATTERN_STRICT_DATE_OPTIONAL_TIME =
            PATTERN_YYYYMMDD_DASH + SPLITTER_T + PATTERN_HHMMSS_COLON + SPLITTER_DOT + PATTERN_MILLISECONDS + SPLITTER_Z;

    /**
     * 日期格式化：yyyy-MM-dd
     */
    public static final DateTimeFormatter FORMATTER_YYYYMMDD;

    static {
        FORMATTER_YYYYMMDD = new DateTimeFormatterBuilder().appendPattern(PATTERN_YYYYMMDD).toFormatter();
    }

    /**
     * 日期格式化：HH:mm:ss
     */
    public static final DateTimeFormatter FORMATTER_HHMMSS;

    static {
        FORMATTER_HHMMSS = new DateTimeFormatterBuilder().appendPattern(PATTERN_HHMMSS).toFormatter();
    }

    /**
     * 日期格式化：yyyy-MM-dd HH:mm:ss
     */
    public static final DateTimeFormatter FORMATTER_YYYYMMDDHHMMSS;

    static {
        FORMATTER_YYYYMMDDHHMMSS = new DateTimeFormatterBuilder().appendPattern(PATTERN_YYYYMMDDHHMMSS).toFormatter();
    }

    /**
     * 日期格式化：yyyy-MM-dd HH:mm:ss.SSS
     */
    public static final DateTimeFormatter FORMATTER_YYYYMMDDHHMMSSZZZ;

    static {
        FORMATTER_YYYYMMDDHHMMSSZZZ = new DateTimeFormatterBuilder().appendPattern(PATTERN_YYYYMMDDHHMMSSZZZ).toFormatter();
    }

    /**
     * The datetime.
     */
    private LocalDateTime localDateTime;

    /**
     * Constructor.
     * Obtains the current date-time from the system clock in the default time-zone.
     */
    EksDate() {
        this.localDateTime = LocalDateTime.now();
    }

    /**
     * Constructor.
     */
    private EksDate(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            this.localDateTime = LocalDateTime.now();
        } else {
            this.localDateTime = localDateTime;
        }
    }

    /**
     * * 获取格式化类，如果缓存中有则直接返回，否则保存到缓存中，下次获取更方便
     *
     * @param pattern 格式字符串
     * @return DateTimeFormatter
     */
    @Nonnull
    public static DateTimeFormatter ofPattern(@Nonnull final String pattern) {
        switch (Objects.requireNonNull(pattern)) {
            case PATTERN_YYYYMMDD:
                return FORMATTER_YYYYMMDD;
            case PATTERN_HHMMSS:
                return FORMATTER_HHMMSS;
            case PATTERN_YYYYMMDDHHMMSS:
                return FORMATTER_YYYYMMDDHHMMSS;
            case PATTERN_YYYYMMDDHHMMSSZZZ:
                return FORMATTER_YYYYMMDDHHMMSSZZZ;
            default:
                DateTimeFormatter formatter = FORMATTER_CONCURRENT_HASH_MAP.get(pattern);
                if (formatter == null) {
                    formatter = DateTimeFormatter.ofPattern(pattern);
                    DateTimeFormatter existing = FORMATTER_CONCURRENT_HASH_MAP.putIfAbsent(pattern, formatter);
                    if (existing != null) {
                        formatter = existing;
                    }
                }
                return formatter;
        }
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 获取当前日期时间
     * Obtains the current date-time from the system clock in the default time-zone.
     *
     * @return The current date-time
     */
    @Nonnull
    public static EksDate now() {
        return new EksDate();
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 根据日期时间字符串创建EksDate实例
     * Obtains an instance of {@code EksDate} from default pattern [yyyy-MM-dd] or [yyyy-MM-dd HH:mm:ss]
     *
     * @param text 日期时间字符串，格式：yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss
     * @return the local date-time, not null
     * @throws IllegalArgumentException if the string not match
     */
    @Nonnull
    public static EksDate of(@Nullable final String text) {
        if (text == null) {
            return new EksDate();
        } else if (isDate(text)) {
            return new EksDate(LocalDate.parse(text, FORMATTER_YYYYMMDD).atStartOfDay());
        } else if (isDateTime(text)) {
            return new EksDate(LocalDateTime.parse(text, FORMATTER_YYYYMMDDHHMMSS));
        } else {
            throw new IllegalArgumentException("The text [" + text +
                    "] not match the default pattern [yyyy-MM-dd] or [yyyy-MM-dd HH:mm:ss]");
        }
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 根据日期时间字符串、日期时间格式创建EksDate实例
     *
     * @param text    日期时间字符串
     * @param pattern 日期时间格式
     * @return the date-time，not null
     * @throws NullPointerException     if {@code text} or {@code pattern} is {@code null}
     * @throws IllegalArgumentException if the pattern is invalid
     */
    @Nonnull
    public static EksDate of(@Nonnull final String text, @Nonnull final String pattern) {
        Objects.requireNonNull(text);
        switch (Objects.requireNonNull(pattern)) {
            case PATTERN_YYYYMMDD:
                return new EksDate(LocalDate.parse(text, FORMATTER_YYYYMMDD).atStartOfDay());
            case PATTERN_YYYYMMDDHHMMSS:
                return new EksDate(LocalDateTime.parse(text, FORMATTER_YYYYMMDDHHMMSS));
            default:
                LocalDateTime localDateTime = LocalDateTime.now();
                TemporalAccessor accessor = ofPattern(pattern).parse(text);
                int year = accessor.isSupported(ChronoField.YEAR) ?
                        accessor.get(ChronoField.YEAR) : localDateTime.getYear();
                int month = accessor.isSupported(ChronoField.MONTH_OF_YEAR) ?
                        accessor.get(ChronoField.MONTH_OF_YEAR) : localDateTime.getMonthValue();
                int dayOfMonth = accessor.isSupported(ChronoField.DAY_OF_MONTH) ?
                        accessor.get(ChronoField.DAY_OF_MONTH) : localDateTime.getDayOfMonth();
                int hour = accessor.isSupported(ChronoField.HOUR_OF_DAY) ?
                        accessor.get(ChronoField.HOUR_OF_DAY) : localDateTime.getHour();
                int minute = accessor.isSupported(ChronoField.MINUTE_OF_HOUR) ?
                        accessor.get(ChronoField.MINUTE_OF_HOUR) : localDateTime.getMinute();
                int second = accessor.isSupported(ChronoField.SECOND_OF_MINUTE) ?
                        accessor.get(ChronoField.SECOND_OF_MINUTE) : localDateTime.getSecond();
                int milli = accessor.isSupported(ChronoField.MILLI_OF_SECOND) ?
                        accessor.get(ChronoField.MILLI_OF_SECOND) : 0;
                return of(year, month, dayOfMonth, hour, minute, second).withMilliseconds(milli);
        }
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 根据日期时间的毫秒数创建EksDate实例
     *
     * @param millis 日期时间的毫秒数
     * @return the date-time, not null
     */
    @Nonnull
    public static EksDate of(long millis) {
        return new EksDate(Instant.ofEpochMilli(millis).atZone(ZoneId.systemDefault()).toLocalDateTime());
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 根据年月日创建EksDate实例
     *
     * @param year       the year to represent, from MIN_YEAR to MAX_YEAR
     * @param month      the month-of-year to represent, from 1 (January) to 12 (December)
     * @param dayOfMonth the day-of-month to represent, from 1 to 31
     * @return the local date-time, not null
     * @throws DateTimeException if the value of any field is out of range,
     *                           or if the day-of-month is invalid for the month-year
     */
    @Nonnull
    public static EksDate of(int year, int month, int dayOfMonth) {
        return new EksDate(LocalDate.of(year, month, dayOfMonth).atStartOfDay());
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 根据年月日时分秒创建EksDate实例
     *
     * @param year       the year to represent, from MIN_YEAR to MAX_YEAR
     * @param month      the month-of-year to represent, from 1 (January) to 12 (December)
     * @param dayOfMonth the day-of-month to represent, from 1 to 31
     * @param hour       the hour-of-day to represent, from 0 to 23
     * @param minute     the minute-of-hour to represent, from 0 to 59
     * @param second     the second-of-minute to represent, from 0 to 59
     * @return the local date-time, not null
     * @throws DateTimeException if the value of any field is out of range,
     *                           or if the day-of-month is invalid for the month-year
     */
    @Nonnull
    public static EksDate of(int year, int month, int dayOfMonth, int hour, int minute, int second) {
        return new EksDate(LocalDateTime.of(year, month, dayOfMonth, hour, minute, second));
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 根据日期时间创建EksDate实例
     *
     * @param date 日期时间
     * @return the date-time, not null
     * @throws NullPointerException if {@code date} is {@code null}
     */
    @Nonnull
    public static EksDate of(@Nonnull final Instant date) {
        validateDateNotNull(date);
        return new EksDate(date.atZone(ZoneId.systemDefault()).toLocalDateTime());
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 根据日期时间创建EksDate实例
     *
     * @param date 日期时间
     * @return the date-time, not null
     * @throws NullPointerException if {@code date} is {@code null}
     */
    @Nonnull
    public static EksDate of(@Nonnull final Calendar date) {
        validateDateNotNull(date);
        return new EksDate(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 根据日期时间创建EksDate实例
     *
     * @param date 日期时间
     * @return the date-time, not null
     * @throws NullPointerException if {@code date} is {@code null}
     */
    @Nonnull
    public static EksDate of(@Nonnull final Date date) {
        return new EksDate(asLocalDateTime(date));
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 根据日期时间创建EksDate实例
     *
     * @param date 日期时间
     * @return the date-time, not null
     * @throws NullPointerException if {@code date} is {@code null}
     */
    @Nonnull
    public static EksDate of(@Nonnull final LocalDate date) {
        validateDateNotNull(date);
        return new EksDate(date.atStartOfDay());
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 根据日期时间创建EksDate实例
     *
     * @param date 日期时间
     * @return the date-time, not null
     * @throws NullPointerException if {@code date} is {@code null}
     */
    @Nonnull
    public static EksDate of(@Nonnull final LocalDateTime date) {
        validateDateNotNull(date);
        return new EksDate(date);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * *判断字符串是否日期格式：yyyy-MM-dd
     *
     * @param text 日期字符串
     * @return boolean
     */
    public static boolean isDate(@Nullable final CharSequence text) {
        return isDateTimeFormat(text, PATTERN_YYYYMMDD);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * *判断字符串是否日期时间格式：yyyy-MM-dd HH:mm:ss
     *
     * @param text 日期时间字符串
     * @return boolean
     */
    public static boolean isDateTime(@Nullable final CharSequence text) {
        return isDateTimeFormat(text, PATTERN_YYYYMMDDHHMMSS);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 判断字符串是否日期格式
     *
     * @param text    日期字符串
     * @param pattern 格式
     * @return boolean
     */
    public static boolean isDateTimeFormat(@Nullable final CharSequence text, @Nullable final String pattern) {
        if (text == null || pattern == null) {
            return false;
        }
        try {
            TemporalAccessor accessor = ofPattern(pattern).parse(text);
            return accessor.isSupported(ChronoField.YEAR)
                    || accessor.isSupported(ChronoField.MONTH_OF_YEAR)
                    || accessor.isSupported(ChronoField.DAY_OF_MONTH)
                    || accessor.isSupported(ChronoField.HOUR_OF_DAY)
                    || accessor.isSupported(ChronoField.MINUTE_OF_HOUR)
                    || accessor.isSupported(ChronoField.SECOND_OF_MINUTE)
                    || accessor.isSupported(ChronoField.MILLI_OF_SECOND);
        } catch (Exception e) {
            return false;
        }
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 日期转换
     *
     * @param date 日期
     * @return Date
     * @throws IllegalArgumentException if the date is null
     */
    @Nonnull
    public static Date asDate(@Nonnull final LocalDate date) {
        validateDateNotNull(date);
        return Date.from(date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 日期时间转换
     *
     * @param date 日期时间
     * @return Date
     * @throws IllegalArgumentException if the date is null
     */
    @Nonnull
    public static Date asDate(@Nonnull final LocalDateTime date) {
        validateDateNotNull(date);
        return Date.from(date.atZone(ZoneId.systemDefault()).toInstant());
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 日期转换
     *
     * @param date 日期时间
     * @return LocalDate
     * @throws IllegalArgumentException if the date is null
     */
    @Nonnull
    public static LocalDate asLocalDate(@Nonnull final Date date) {
        validateDateNotNull(date);
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 日期时间转换
     *
     * @param date 日期时间
     * @return LocalDateTime
     * @throws IllegalArgumentException if the date is null
     */
    @Nonnull
    public static LocalDateTime asLocalDateTime(@Nonnull final Date date) {
        validateDateNotNull(date);
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * Converts a {@code Date} into a {@code Calendar}.
     *
     * @param date the date to convert to a Calendar
     * @return the created Calendar
     * @throws IllegalArgumentException if the date is null
     */
    @Nonnull
    public static Calendar asCalendar(@Nonnull final Date date) {
        validateDateNotNull(date);
        final Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 加上年数
     *
     * @param years the years to add, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate plusYears(final long years) {
        localDateTime = localDateTime.plusYears(years);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 减去年数
     *
     * @param years the years to subtract, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate minusYears(final long years) {
        localDateTime = localDateTime.minusYears(years);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 加上月数
     *
     * @param months the months to add, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate plusMonths(final long months) {
        localDateTime = localDateTime.plusMonths(months);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 减去月数
     *
     * @param months the months to subtract, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate minusMonths(final long months) {
        localDateTime = localDateTime.minusMonths(months);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 加上星期数
     *
     * @param weeks the weeks to add, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate plusWeeks(final long weeks) {
        localDateTime = localDateTime.plusWeeks(weeks);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 减去星期数
     *
     * @param weeks the weeks to subtract, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate minusWeeks(final long weeks) {
        localDateTime = localDateTime.minusWeeks(weeks);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 加上天数
     *
     * @param days the days to add, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate plusDays(final long days) {
        localDateTime = localDateTime.plusDays(days);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 减去天数
     *
     * @param days the days to subtract, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate minusDays(final long days) {
        localDateTime = localDateTime.minusDays(days);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 加上小时数
     *
     * @param hours the hours to add, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate plusHours(final long hours) {
        localDateTime = localDateTime.plusHours(hours);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 减去小时数
     *
     * @param hours the hours to subtract, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate minusHours(final long hours) {
        localDateTime = localDateTime.minusHours(hours);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 加上分钟数
     *
     * @param minutes the minutes to add, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate plusMinutes(final long minutes) {
        localDateTime = localDateTime.plusMinutes(minutes);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 减去分钟数
     *
     * @param minutes the minutes to subtract, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate minusMinutes(final long minutes) {
        localDateTime = localDateTime.minusMinutes(minutes);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 加上秒数
     *
     * @param seconds the seconds to add, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate plusSeconds(final long seconds) {
        localDateTime = localDateTime.plusSeconds(seconds);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 减去秒数
     *
     * @param seconds the seconds to subtract, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate minusSeconds(final long seconds) {
        localDateTime = localDateTime.minusSeconds(seconds);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 加上毫秒数
     *
     * @param milliseconds the milliseconds to add, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate plusMilliseconds(final long milliseconds) {
        localDateTime = localDateTime.plus(milliseconds, ChronoUnit.MILLIS);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 减去毫秒数
     *
     * @param milliseconds the milliseconds to subtract, may be negative
     * @return this EksDate instance
     * @throws DateTimeException if the result exceeds the supported date range
     */
    @Nonnull
    public EksDate minusMilliseconds(final long milliseconds) {
        localDateTime = localDateTime.minus(milliseconds, ChronoUnit.MILLIS);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定年份
     *
     * @param year the year to set in the result, from MIN_YEAR to MAX_YEAR
     * @return this EksDate instance
     * @throws DateTimeException if the year value is invalid
     */
    @Nonnull
    public EksDate withYear(final int year) {
        ChronoField.YEAR_OF_ERA.checkValidValue(year);
        localDateTime = localDateTime.withYear(year);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定年份
     *
     * @param year the year to set in the result, from MIN_YEAR to MAX_YEAR
     * @return this EksDate instance
     * @throws DateTimeException if the year value is invalid
     */
    @Nonnull
    public EksDate withYear(final long year) {
        return withYear((int) year);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定月份
     *
     * @param month the month-of-year to set in the result, from 1 (January) to 12 (December)
     * @return this EksDate instance
     * @throws DateTimeException if the month-of-year value is invalid
     */
    @Nonnull
    public EksDate withMonth(final int month) {
        ChronoField.MONTH_OF_YEAR.checkValidValue(month);
        localDateTime = localDateTime.withMonth(month);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定月份
     *
     * @param month the month-of-year to set in the result, from 1 (January) to 12 (December)
     * @return this EksDate instance
     * @throws DateTimeException if the month-of-year value is invalid
     */
    @Nonnull
    public EksDate withMonth(final long month) {
        return withMonth((int) month);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定月份中的天数
     *
     * @param dayOfMonth the day-of-month to set in the result, from 1 to 28-31
     * @return this EksDate instance, not null
     * @throws DateTimeException if the day-of-month value is invalid,
     *                           or if the day-of-month is invalid for the month-year
     */
    @Nonnull
    public EksDate withDayOfMonth(final int dayOfMonth) {
        ChronoField.DAY_OF_MONTH.checkValidValue(dayOfMonth);
        localDateTime = localDateTime.withDayOfMonth(dayOfMonth);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定月份中的天数
     *
     * @param dayOfMonth the day-of-month to set in the result, from 1 to 28-31
     * @return this EksDate instance, not null
     * @throws DateTimeException if the day-of-month value is invalid,
     *                           or if the day-of-month is invalid for the month-year
     */
    @Nonnull
    public EksDate withDayOfMonth(final long dayOfMonth) {
        return withDayOfMonth((int) dayOfMonth);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定年份中的天数
     *
     * @param dayOfYear the day-of-year to set in the result, from 1 to 365-366
     * @return this EksDate instance, not null
     * @throws DateTimeException if the day-of-year value is invalid,
     *                           or if the day-of-year is invalid for the year
     */
    @Nonnull
    public EksDate withDayOfYear(final int dayOfYear) {
        ChronoField.DAY_OF_YEAR.checkValidValue(dayOfYear);
        localDateTime = localDateTime.withDayOfYear(dayOfYear);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定年份中的天数
     *
     * @param dayOfYear the day-of-year to set in the result, from 1 to 365-366
     * @return this EksDate instance, not null
     * @throws DateTimeException if the day-of-year value is invalid,
     *                           or if the day-of-year is invalid for the year
     */
    @Nonnull
    public EksDate withDayOfYear(final long dayOfYear) {
        return withDayOfYear((int) dayOfYear);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定小时数
     *
     * @param hour the hour-of-day to set in the result, from 0 to 23
     * @return this EksDate instance, not null
     * @throws DateTimeException if the hour value is invalid
     */
    @Nonnull
    public EksDate withHour(final int hour) {
        ChronoField.HOUR_OF_DAY.checkValidValue(hour);
        localDateTime = localDateTime.withHour(hour);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定小时数
     *
     * @param hour the hour-of-day to set in the result, from 0 to 23
     * @return this EksDate instance, not null
     * @throws DateTimeException if the hour value is invalid
     */
    @Nonnull
    public EksDate withHour(final long hour) {
        return withHour((int) hour);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定分钟数
     *
     * @param minute the minute-of-hour to set in the result, from 0 to 59
     * @return this EksDate instance, not null
     * @throws DateTimeException if the minute value is invalid
     */
    @Nonnull
    public EksDate withMinute(final int minute) {
        ChronoField.MINUTE_OF_HOUR.checkValidValue(minute);
        localDateTime = localDateTime.withMinute(minute);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定分钟数
     *
     * @param minute the minute-of-hour to set in the result, from 0 to 59
     * @return this EksDate instance, not null
     * @throws DateTimeException if the minute value is invalid
     */
    @Nonnull
    public EksDate withMinute(final long minute) {
        return withMinute((int) minute);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定秒数
     *
     * @param second the second-of-minute to set in the result, from 0 to 59
     * @return this EksDate instance, not null
     * @throws DateTimeException if the second value is invalid
     */
    @Nonnull
    public EksDate withSecond(final int second) {
        ChronoField.SECOND_OF_MINUTE.checkValidValue(second);
        localDateTime = localDateTime.withSecond(second);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定秒数
     *
     * @param second the second-of-minute to set in the result, from 0 to 59
     * @return this EksDate instance, not null
     * @throws DateTimeException if the second value is invalid
     */
    @Nonnull
    public EksDate withSecond(final long second) {
        return withSecond((int) second);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定毫秒数
     *
     * @param millisecond the MilliOfSecond to set in the result, from 0 to 999
     * @return this EksDate instance, not null
     * @throws DateTimeException if the millisecond value is invalid
     */
    @Nonnull
    public EksDate withMilliseconds(final int millisecond) {
        ChronoField.MILLI_OF_SECOND.checkValidValue(millisecond);
        int nanos = (int) NANOS_PER_MILLISECOND;
        localDateTime = localDateTime.withNano(millisecond * nanos);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定毫秒数
     *
     * @param millisecond the MilliOfSecond to set in the result, from 0 to 999
     * @return this EksDate instance, not null
     * @throws DateTimeException if the millisecond value is invalid
     */
    @Nonnull
    public EksDate withMilliseconds(final long millisecond) {
        return withMilliseconds((int) millisecond);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定纳秒数
     *
     * @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,999
     * @return this EksDate instance, not null
     * @throws DateTimeException if the nano value is invalid
     */
    @Nonnull
    public EksDate withNano(final int nanoOfSecond) {
        ChronoField.NANO_OF_SECOND.checkValidValue(nanoOfSecond);
        localDateTime = localDateTime.withNano(nanoOfSecond);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定纳秒数
     *
     * @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,999
     * @return this EksDate instance, not null
     * @throws DateTimeException if the nano value is invalid
     */
    @Nonnull
    public EksDate withNano(final long nanoOfSecond) {
        return withNano((int) nanoOfSecond);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定月份为最小值，即: 1
     *
     * @return this EksDate instance
     */
    @Nonnull
    public EksDate withMinMonth() {
        return withMonth(1);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定月份中的天数为最小值，即: 1
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMinDay() {
        return withDayOfMonth(1);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定小时数为最小值，即: 0
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMinHour() {
        return withHour(0);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定分钟数为最小值，即: 0
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMinMinute() {
        return withMinute(0);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定秒数为最小值，即: 0
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMinSecond() {
        return withSecond(0);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定毫秒数为最小值，即: 0
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMinMilliseconds() {
        return withMilliseconds(0);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定时分秒为最小值，即: 00:00:00
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMinHHMMSS() {
        return withMinHour().withMinMinute().withMinSecond();
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定时分秒毫秒为最小值，即: 00:00:00.000
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMinHHMMSSZZZ() {
        return withMinHHMMSS().withMinMilliseconds();
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定月份为最大值，即: 12
     *
     * @return this EksDate instance
     */
    @Nonnull
    public EksDate withMaxMonth() {
        return withMonth(12);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定月份中的天数为最大值，即: 28-31
     * <p>
     * 1月31天；
     * 2月闰年29天，非闰年28天；
     * 3月31天；
     * 4月30天；
     * 5月31天；
     * 6月30天；
     * 7月31天；
     * 8月31天；
     * 9月30天；
     * 10月31天；
     * 11月30天；
     * 12月31天；
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMaxDay() {
        int dom = 31;
        switch (localDateTime.getMonthValue()) {
            case 2:
                dom = (IsoChronology.INSTANCE.isLeapYear(localDateTime.getYear()) ? 29 : 28);
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                dom = 30;
                break;
            default:
        }
        return withDayOfMonth(dom);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定小时数为最大值，即: 23
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMaxHour() {
        return withHour(23);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定分钟数为最大值，即: 59
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMaxMinute() {
        return withMinute(59);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定秒数为最大值，即: 59
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMaxSecond() {
        return withSecond(59);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定毫秒数为最大值，即: 999
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMaxMilliseconds() {
        return withMilliseconds(999);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定时分秒为最大值，即: 23:59:59
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMaxHHMMSS() {
        return withMaxHour().withMaxMinute().withMaxSecond();
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定时分秒毫秒为最大值，即: 23:59:59.999
     *
     * @return this EksDate instance, not null
     */
    @Nonnull
    public EksDate withMaxHHMMSSZZZ() {
        return withMaxHHMMSS().withMaxMilliseconds();
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 指定为营业时间，即当天6点到第二天6点
     *
     * @param isEnd 是否营业结束时间
     * @return a EksDate of business date-time
     */
    @Nonnull
    public EksDate withBusinessDateTime(final boolean isEnd) {
        int hour = localDateTime.getHour();
        if (hour < BUSINESS_START_HOUR && !isEnd) {
            localDateTime = localDateTime.minusDays(1);
        } else if (hour >= BUSINESS_START_HOUR && isEnd) {
            localDateTime = localDateTime.plusDays(1);
        }
        localDateTime = localDateTime.withHour(BUSINESS_START_HOUR);
        localDateTime = localDateTime.withMinute(0);
        localDateTime = localDateTime.withSecond(0);
        localDateTime = localDateTime.withNano(0);
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 最小日期
     *
     * @param dates 比较日期，可多个
     * @return min date-time EksDate
     */
    @Nonnull
    public EksDate min(@Nullable final Date... dates) {
        if (dates == null) {
            return this;
        }
        for (Date date : dates) {
            if (date == null) {
                continue;
            }
            LocalDateTime other = asLocalDateTime(date);
            if (localDateTime.isAfter(other)) {
                localDateTime = other;
            }
        }
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 最小日期
     *
     * @param dates 比较日期，可多个
     * @return min date-time EksDate
     */
    @Nonnull
    public EksDate min(@Nullable final LocalDate... dates) {
        if (dates == null) {
            return this;
        }
        for (LocalDate date : dates) {
            if (date == null) {
                continue;
            }
            if (localDateTime.isAfter(date.atStartOfDay())) {
                localDateTime = date.atStartOfDay();
            }
        }
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 最小日期
     *
     * @param dates 比较日期，可多个
     * @return min date-time EksDate
     */
    @Nonnull
    public EksDate min(@Nullable final LocalDateTime... dates) {
        if (dates == null) {
            return this;
        }
        for (LocalDateTime date : dates) {
            if (date == null) {
                continue;
            }
            if (localDateTime.isAfter(date)) {
                localDateTime = date;
            }
        }
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 最大日期
     *
     * @param dates 比较日期，可多个
     * @return max date-time EksDate
     */
    @Nonnull
    public EksDate max(@Nullable final Date... dates) {
        if (dates == null) {
            return this;
        }
        for (Date date : dates) {
            if (date == null) {
                continue;
            }
            LocalDateTime other = asLocalDateTime(date);
            if (localDateTime.isBefore(other)) {
                localDateTime = other;
            }
        }
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 最大日期
     *
     * @param dates 比较日期，可多个
     * @return max date-time EksDate
     */
    @Nonnull
    public EksDate max(@Nullable final LocalDate... dates) {
        if (dates == null) {
            return this;
        }
        for (LocalDate date : dates) {
            if (date == null) {
                continue;
            }
            if (localDateTime.isBefore(date.atStartOfDay())) {
                localDateTime = date.atStartOfDay();
            }
        }
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 最大日期
     *
     * @param dates 比较日期，可多个
     * @return max date-time EksDate
     */
    @Nonnull
    public EksDate max(@Nullable final LocalDateTime... dates) {
        if (dates == null) {
            return this;
        }
        for (LocalDateTime date : dates) {
            if (date == null) {
                continue;
            }
            if (localDateTime.isBefore(date)) {
                localDateTime = date;
            }
        }
        return this;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 根据当前日期时间创建新的EksDate实例
     *
     * @return The new EksDate, not null
     */
    @Nonnull
    public EksDate copy() {
        return new EksDate(localDateTime);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 验证日期是否为空，如果为空则抛出异常
     *
     * @param date 日期
     * @throws NullPointerException if {@code date} is {@code null}
     */
    private static void validateDateNotNull(final Object date) {
        Objects.requireNonNull(date, "date");
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 是否润年
     *
     * @param year The year number
     * @return 是否润年
     */
    public static boolean isLeapYear(int year) {
        return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 转换为日期类
     *
     * @return The date-time
     */
    @Nonnull
    public Date toDate() {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * Converts a {@code Date} into a {@code Calendar}.
     *
     * @return the created Calendar
     */
    @Nonnull
    public Calendar toCalendar() {
        final Calendar c = Calendar.getInstance();
        c.setTimeInMillis(toEpochMilli());
        return c;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 转换为日期类
     *
     * @return The date-time
     */
    @Nonnull
    public LocalDate toLocalDate() {
        return localDateTime.toLocalDate();
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * Gets the {@code LocalTime} part of this date-time.
     * <p>
     * This returns a {@code LocalTime} with the same hour, minute, second and
     * nanosecond as this date-time.
     *
     * @return the time part of this date-time, not null
     */
    @Nonnull
    public LocalTime toLocalTime() {
        return localDateTime.toLocalTime();
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 转换为日期类
     *
     * @return The date-time
     */
    @Nonnull
    public LocalDateTime toLocalDateTime() {
        return localDateTime;
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * Converts this date-time to the number of milliseconds from the epoch of 1970-01-01T00:00:00Z.
     *
     * @return milliseconds
     */
    public long toEpochMilli() {
        return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 转换为字符串，格式为：yyyy-MM-dd HH:mm:ss.SSS
     *
     * @return The date-time
     */
    @Nonnull
    @Override
    public String toString() {
        return localDateTime.format(FORMATTER_YYYYMMDDHHMMSSZZZ);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 转换为指定格式的字符串
     *
     * @param pattern 格式
     * @return The date-time
     * @throws DateTimeException if an error occurs during printing
     * @see #ofPattern(String)
     */
    @Nonnull
    public String toString(@Nullable final String pattern) {
        if (pattern == null) {
            return toString();
        }
        return localDateTime.format(ofPattern(pattern));
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 转换为字符串，格式为：yyyy-MM-dd
     *
     * @return The date-time
     */
    @Nonnull
    public String toDateString() {
        return localDateTime.format(FORMATTER_YYYYMMDD);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 转换为字符串，格式为：yyyy-MM-dd
     *
     * @return The date-time
     */
    @Nonnull
    public String toTimeString() {
        return localDateTime.format(FORMATTER_HHMMSS);
    }

    //-----------------------------------------------------------------------------------------------------------------

    /**
     * * 转换为字符串，格式为：yyyy-MM-dd HH:mm:ss
     *
     * @return The date-time
     */
    @Nonnull
    public String toDateTimeString() {
        return localDateTime.format(FORMATTER_YYYYMMDDHHMMSS);
    }

}
